
#include <bondlib/SSVContainer.h>
#include <bondlib/QBProviceInfo.h>
#include <bondlib/QBSwSectorInfo.h>
#include <bondlib/QBIssuerInfo.h>
#include <bondlib/BondDict.h>
#include "SortBuffer.h"
#include <qglobal.h>
namespace detail{

#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
	namespace{
		enum kSortType{
			kSortTypeString,
			kSortTypeDouble,
			kSortTypeInt,
			kSortTypeChar,
			kSortTypeBidLimit,			// double	bottom,top
			kSortTypeMaturityTermEnd,	//
			kSortTypeTermToMaturity,	
			kSortTypeIssuePeriod		// 
		};

		int CompareDouble(double dValue1, double dValue2)
		{
			double delta = dValue1 - dValue2;
			return GetDoubleFlag(delta);
		}

		int StringComparator(const void* f1, const void* f2)
		{
			return strcmp((const char*)f1, (const char*)f2);
		}
		int DoubleComparator(const void* f1, const void* f2)
		{
			double delta = *((const double*)f1) - *((const double*)f2);
			return GetDoubleFlag(delta);
		}
		int IntComparator(const void* f1, const void* f2)
		{
			int i1 = *((const int*)f1), i2 = *((const int*)f2);
			return i1 == i2 ? 0 : (i1 < i2 ? -1 : 1);
		}
		int CharComparator(const void* f1, const void* f2)
		{
			char i1 = *((const char*)f1), i2 = *((const char*)f2);
			return i1 == i2 ? 0 : (i1 < i2 ? -1 : 1);
		}
		int BidLimitComparator(const void* f1, const void* f2)
		{
			double bot1 = *((const double*)f1), top1 = *((const double*)f1 + 1);
			double bot2 = *((const double*)f2), top2 = *((const double*)f2 + 1);
			if (bot1 == bot2)
				return CompareDouble(top1, top2);
			return CompareDouble(bot1, bot2);
		}
		int MaturityTermEndComparator(const void* f1, const void* f2)
		{
			int b1 = *((const int*)f1), b2 = *((const int*)f2);
			std::string iMaturityTerm_s = GetBond(b1).GetMaturityTerm();
			std::string jMaturityTerm_s = GetBond(b2).GetMaturityTerm();
			int iMaturityTerm = CSSVContainer::CalMaturityTerm(iMaturityTerm_s);
			int jMaturityTerm = CSSVContainer::CalMaturityTerm(jMaturityTerm_s);
			if (iMaturityTerm != jMaturityTerm)
				return iMaturityTerm - jMaturityTerm;
			else
			{
				int iComp = strcmp(GetBond(b1).GetTermToMaturity(), GetBond(b2).GetTermToMaturity());
				if (0 == iComp)
					return CSSVContainer::CalMaturityType(iMaturityTerm_s) - CSSVContainer::CalMaturityType(jMaturityTerm_s);
				else
					return iComp;
			}
		}
		int TermToMaturityComparator(const void* f1, const void* f2)
		{
			int b1 = *((const int*)f1), b2 = *((const int*)f2);
			std::string iMaturityTerm_s = GetBond(b1).GetTermToMaturity();
			std::string jMaturityTerm_s = GetBond(b2).GetTermToMaturity();
			int iMaturityTerm = CSSVContainer::CalMaturityTerm(iMaturityTerm_s);
			int jMaturityTerm = CSSVContainer::CalMaturityTerm(jMaturityTerm_s);
			if (iMaturityTerm != jMaturityTerm)
				return iMaturityTerm - jMaturityTerm;
			else
			{
				int iComp = strcmp(GetBond(b1).GetTermToMaturity(), GetBond(b2).GetTermToMaturity());
				if (0 == iComp)
					return CSSVContainer::CalMaturityType(iMaturityTerm_s) - CSSVContainer::CalMaturityType(jMaturityTerm_s);
				else
					return iComp;
			}
		}
		int IssuePeriodComparator(const void* f1, const void* f2)
		{
			const IssuePeriod& ip1 = *((const IssuePeriod*)f1);
			const IssuePeriod& ip2 = *((const IssuePeriod*)f2);
			if (ip1.nAscend == ip2.nAscend)
			{
				if (ip1.nAscend == 2)//都是募集时间，则按字符串排序
					return strcmp(GetBond(ip1.nBondIndex).GetIssuePeriod(), GetBond(ip2.nBondIndex).GetIssuePeriod());
				return (ip1.nDate == ip2.nDate) ? 0 : ((ip1.nDate > ip2.nDate) ? 1 : -1);
			}
			return ip1.nAscend > ip2.nAscend ? 1 : -1;

		}
	}
	//////////////////////////////////////////////////////////////////////////
	SortKeyManager& SortKeyManager::Get()
	{
		static SortKeyManager gs_sort_key_manager;
		return gs_sort_key_manager;
	}
	SortKeyManager::SortKeyManager()
	{
#define SetField(COL,TYPE,SIZE) SetFieldImpl(COL,#COL,TYPE,SIZE);
		SetField(VBOND_CODE, kSortTypeString, sizeof(tBondCode));
		SetField(VSHORT_NAME, kSortTypeString, 32);//max(m_sShortName,m_sShortNameEn));
		SetField(VSHORT_NAME_EN, kSortTypeString, 128);//max(m_sShortName,m_sShortNameEn));
		SetField(VEXPIRY_DATE, kSortTypeDouble, sizeof(double));
		SetField(VBUYVOL, kSortTypeDouble, sizeof(double));
		SetField(VBUYPRICE, kSortTypeDouble, sizeof(double));
		SetField(VSELLVOL, kSortTypeDouble, sizeof(double));
		SetField(VSELLPRICE, kSortTypeDouble, sizeof(double));
		SetField(VMODIFY_TIME, kSortTypeDouble, sizeof(double));
		SetField(VRATING, kSortTypeInt, sizeof(int));
		SetField(VCDCRATING, kSortTypeInt, sizeof(int));
		SetField(VCSIRATING, kSortTypeInt, sizeof(int));
		SetField(VCBRRATING, kSortTypeInt, sizeof(int));
		SetField(VESTBPRICEPRE, kSortTypeDouble, sizeof(double));
		SetField(VESTBPRICETODAY, kSortTypeDouble, sizeof(double));
		SetField(VESTBCLEPRICE, kSortTypeDouble, sizeof(double));
		//case VBOND_TYPE:/*sort_bond_type*/break;
		//case VBUYCLEPRICE:/*sort_bcle_price*/break;
		//case VSELLCLEPRICE:/*sort_scle_price*/break;
		//case VMATURITY_DATE:/*sort_maturity_date*/break;
		//case VCROSSMARKET:/*sort_cross_market*/break;
		SetField(VBROKERKEY, kSortTypeInt, sizeof(int));
		SetField(VISSUERRATING, kSortTypeInt, sizeof(int));
		SetField(VBONDRATING, kSortTypeInt, sizeof(int));
		SetField(INDICATIVE_PRICE, kSortTypeDouble, sizeof(double));
		SetField(VTKNPRICE, kSortTypeDouble, sizeof(double));
		SetField(BSVTKPRICE, kSortTypeDouble, sizeof(double));
		SetField(PLANNED_ISSURE_AMOUNT, kSortTypeDouble, sizeof(double));
		SetField(BID_LIMIT, kSortTypeBidLimit, sizeof(double) * 2);
		SetField(AUCTION_LIMIT, kSortTypeBidLimit, sizeof(double) * 2);
		SetField(ISSUE_START_DATE, kSortTypeInt, sizeof(int));
		SetField(PAYMENT_DATE, kSortTypeInt, sizeof(int));
		SetField(LISTED_DATE, kSortTypeInt, sizeof(int));
		SetField(INSTITUTION_TYPE, kSortTypeInt, sizeof(int));
		SetField(ANNOUNCE_DATE, kSortTypeInt, sizeof(int));
		SetField(COUPON_RATE, kSortTypeDouble, sizeof(double));
		SetField(MATURITY_TERM_END, kSortTypeMaturityTermEnd, sizeof(int));
		SetField(TERM_TO_MATURITY, kSortTypeTermToMaturity, sizeof(int));
		SetField(AREA, kSortTypeString, RTL_FIELD_SIZE(QBPROVINCEINFO, Area_Name));//CBondInfo::GetArea()
		SetField(SECTOR, kSortTypeString, RTL_FIELD_SIZE(QBSWSECTORINFO, SW_Name));//CBondInfo::GetSwSector()
		SetField(INTEREST_START_DATE, kSortTypeString, sizeof(tDate8));//CBondInfo::m_sInterestStartDate
		SetField(kInstitutionName, kSortTypeString, RTL_FIELD_SIZE(QBISSUERINFO, Short_Name_C));//CBondInfo::GetInstitutionShortName
		SetField(kIssueEndTime, kSortTypeString, sizeof(tDate8) * 2);//GetIssueStartDate+GetIssueEndTime
		SetField(kActualIssureAmount, kSortTypeDouble, sizeof(double));
		SetField(kIssuerAmount, kSortTypeDouble, sizeof(double));
		SetField(kCouponType, kSortTypeString, RTL_FIELD_SIZE(BondDict, selective_content));//GetCouponTypeName-------------------very large 512
		SetField(kRateType, kSortTypeString, RTL_FIELD_SIZE(BondDict, selective_content));	//  票面 add  by lbl   

		SetField(kDuration, kSortTypeDouble, sizeof(double));
		SetField(kBid_EstPrice, kSortTypeDouble, sizeof(double));
		SetField(kEstPrice_Ofr, kSortTypeDouble, sizeof(double));
		SetField(kOutlook, kSortTypeInt, sizeof(int));//CBondInfo::m_sOutlook;
		SetField(kIssuerPeriod, kSortTypeIssuePeriod, sizeof(IssuePeriod));//compare_IssuePeriod
		SetField(kInstitutionFullName, kSortTypeString, qMax(RTL_FIELD_SIZE(QBISSUERINFO, Short_Name_C), RTL_FIELD_SIZE(QBISSUERINFO, Full_Name_E)));//GetInstitutionFullName
		SetField(ISSUE_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
		SetField(PAYMENT_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
		SetField(LISTED_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
		SetField(ANNOUNCE_DATE_IsuPeriod, kSortTypeInt, sizeof(int));
		SetField(INTEREST_DATE_IsuPeriod, kSortTypeString, sizeof(tDate8));//m_sInterestStartDate
		SetField(kIssueRate, kSortTypeDouble, sizeof(double));
		SetField(kConvRate, kSortTypeDouble, sizeof(double));
		SetField(kTknPrice, kSortTypeDouble, sizeof(double));
		SetField(kCleanPriceDiv, kSortTypeDouble, sizeof(double));
		SetField(kTknYield, kSortTypeDouble, sizeof(double));
		SetField(kYieldDiv, kSortTypeDouble, sizeof(double));
		SetField(kCouponRate, kSortTypeDouble, sizeof(double));
		SetField(kCsiVal, kSortTypeDouble, sizeof(double));
		SetField(kCsiCleanPrice, kSortTypeDouble, sizeof(double));
		SetField(kCdcCleanPrice, kSortTypeDouble, sizeof(double));
		SetField(kOptionType, kSortTypeString, 8);//m_sOptionType
		SetField(kOptionDate, kSortTypeDouble, sizeof(double));
		SetField(kCsi_Cdc, kSortTypeDouble, sizeof(double));
		SetField(kCrossMarket, kSortTypeChar, sizeof(char));
		SetField(kIndustry, kSortTypeString, RTL_FIELD_SIZE(QBSWSECTORINFO, SW_Name));
		SetField(kIndustryEn, kSortTypeString, RTL_FIELD_SIZE(QBSWSECTORINFO, SW_English_Name));
		SetField(kRatingAgency, kSortTypeString, RTL_FIELD_SIZE(QBISSUERINFO, Short_Name_C));

		SetField(VBondType, kSortTypeInt, sizeof(int));
		SetField(VBondIssuer, kSortTypeString, 10);
		SetField(kBondGuarantor, kSortTypeString, 64);
		SetField(kBondGuarantorEn, kSortTypeString, 64);
		SetField(kBondLiquidity, kSortTypeDouble, sizeof(double));
		SetField(kIssuerLiquidity, kSortTypeDouble, sizeof(double));
		SetField(kOutstandingAmount, kSortTypeDouble, sizeof(double));

		SetField(kBid_CsiVal, kSortTypeDouble, sizeof(double));
		SetField(kCsiVal_Ofr, kSortTypeDouble, sizeof(double));
		SetField(kMaturityDate, kSortTypeString, sizeof(tDate8));//m_sMaturityDate
		SetField(kMaturityDate_IsuPeriod, kSortTypeString, sizeof(tDate8));//m_sMaturityDate
		SetField(kDeal_Cdc, kSortTypeDouble, sizeof(double));
		SetField(kDeal_Csi, kSortTypeDouble, sizeof(double));
		SetField(kTknCleanCleanPrice, kSortTypeDouble, sizeof(double));
		SetField(fisse_deal_netprice, kSortTypeDouble, sizeof(double));
		SetField(fisse_deal_fullprice, kSortTypeDouble, sizeof(double));
		SetField(fisse_deal_yield, kSortTypeDouble, sizeof(double));
		SetField(fisse_deal_volumn, kSortTypeDouble, sizeof(double));
		SetField(fisse_deal_amount, kSortTypeDouble, sizeof(double));

		SetField(kABSBondBaseType, kSortTypeString, 32);
		SetField(kABSBondSeries, kSortTypeString, 32);
		SetField(kABSBondIssuer, kSortTypeString, 10);
		SetField(kBondMainUnderwriter, kSortTypeString, 64);
	}
	SortKeyManager::~SortKeyManager()
	{}
	void SortKeyManager::SetFieldImpl(int column, const char* name, int sortType, int bytes)
	{
		// 一次性设置
		FieldInfo fi; fi.column_id = column;
		fi.field_bytes = (bytes % 4 != 0) ? ((bytes / 4 + 1) * 4) : bytes;
		fi.sort_type = sortType;
		fi.column_name = name;
		m_fields[column] = fi;
	}
	bool SortKeyManager::GetFieldInfo(int column, FieldInfo& fi)
	{
		FiledInfoMap::iterator it = m_fields.find(column);
		if (it != m_fields.end())
		{
			fi = it->second;
			return true;
		}
		return false;
	}

	//////////////////////////////////////////////////////////////////////////
	CSortBuffer::CSortBuffer() :m_comp_count(0), m_capcity(0), m_buffer(0)
	{
		//m_bond_reader = new BondReader();

		SetComparator(kSortTypeString, StringComparator);
		SetComparator(kSortTypeDouble, DoubleComparator);
		SetComparator(kSortTypeInt, IntComparator);
		SetComparator(kSortTypeChar, CharComparator);
		SetComparator(kSortTypeBidLimit, BidLimitComparator);
		SetComparator(kSortTypeMaturityTermEnd, MaturityTermEndComparator);
		SetComparator(kSortTypeTermToMaturity, TermToMaturityComparator);
		SetComparator(kSortTypeIssuePeriod, IssuePeriodComparator);


	}
	CSortBuffer::~CSortBuffer()
	{
		if (m_buffer)
		{
			delete[] m_buffer;
			m_buffer = 0;
		}
	}
	void CSortBuffer::SetComparator(int type, FieldComparator comparator)
	{
		m_comparators[type] = comparator;
	}
	FieldComparator CSortBuffer::GetComparator(int type)
	{
		return m_comparators[type];
	}


	int CSortBuffer::CompareRecord(const INDEX& k1, const INDEX& k2)
	{
		// 手动排序过程中的多重比较函数
		int cmp = 0, ncount = m_sortinfos.size();
		m_comp_count++;
		for (int i = 0; i < ncount; i++)
		{
			SortInfo& si = m_sortinfos[i];
			cmp = si.comparator(m_buffer + k1.offset + si.offset, m_buffer + k2.offset + si.offset);
			cmp = si.ascend ? cmp : -cmp;
			if (cmp != 0)
				return cmp;
		}
		return cmp;
	}

	void CSortBuffer::CheckSort()
	{
		int less = 0, large = 0;
		for (int i = 1; i < (int)m_indexes.size(); i++)
		{
			int cmp = CompareRecord(m_indexes[i - 1], m_indexes[i]);
			if (cmp <= 0)less++;
			if (cmp >= 0)large++;
		}
		if (less + 1 < (int)m_indexes.size() && large + 1 < (int)m_indexes.size()){
			log_warning("sort check failed,less:%d large:%d", less, large);
		}
		else{
			log_warning("sort check success,%s", less > 0 ? "asccend" : "desccend");
		}
	}

	char* CSortBuffer::PrepareBuffer(int nCount, int nRecordSize)
	{
		int total_size = nCount*nRecordSize;
		if (m_buffer == 0 || m_capcity < total_size)
		{
			total_size = total_size < 4096 ? 4096 : total_size;
			if (m_buffer)	delete[] m_buffer;
			m_buffer = new char[total_size];
			m_capcity = total_size;
		}
		memset(m_buffer, 0, m_capcity);
		return m_buffer;
	}

	/*
		keys		:	每个KeyType是一条记录的主键,keys是要进行排序的所有记录的主键数组
		sortinfos	:	要进行排序的重次,多个即为多重排序
		recordSize	:	单条记录的大小,要排序的所有字段都在单条记录中,已经包含KeyType
		reader		:	用于根据KeyType读取对应记录的排序字段
	*/
	void CSortBuffer::LoadSortData(std::vector<KeyType>& keys, std::vector<SortInfo>& sortinfos, int recordSize, IBondReader*	reader)
	{
		int nCount = keys.size();
		m_indexes.clear();
		m_indexes.reserve(nCount);
		char* buffer = PrepareBuffer(nCount, recordSize);
		char* end = buffer + m_capcity;
		char* record = buffer;
		for (int i = 0; i < nCount; i++)
		{
			const KeyType& bki = keys[i];

			// RealTimeDealSorter::SetSortInfo中已经将m_record_head_size大小的内存预留
			// 起来,用作KeyType*存储
			*(reinterpret_cast<const KeyType**>(record)) = &bki;
			for (int j = 0; j < (int)sortinfos.size(); j++)
			{
				SortInfo& si = sortinfos[j];
				reader->GetRecordField(&bki, si.column_id, record + si.offset, si.field_bytes);
			}
			record += recordSize;
			Q_ASSERT(record <= end);
			m_indexes.push_back(INDEX(i, i*recordSize));
		}
	}

	void CSortBuffer::Sort(std::vector<KeyType>& keys, const std::vector<SortInfo>& sortinfos, int ncorpid, int recordSize,IBondReader* reader)
	{
		class Comparator{
			CSortBuffer&	m_sort_buffer;
		public:
			Comparator(CSortBuffer& sb) :m_sort_buffer(sb){}
			bool operator()(const INDEX& i1, const INDEX& i2)
			{
				return m_sort_buffer.CompareRecord(i1, i2) < 0;
			}
		};
		if (keys.size() <= 1 || sortinfos.size() < 0)
			return;
		m_sortinfos = sortinfos;
		reader->PreGetRecordField(sortinfos, ncorpid);
		FieldInfo fi;
		int first_col = m_sortinfos[0].column_id;
		if (!SortKeyManager::Get().GetFieldInfo(m_sortinfos[0].column_id, fi))
		{
			log_error("SortKeyManager::GetFieldInfo(VSortKey:%d) failed,", first_col);
			return;
		}

		std::vector<KeyType> temp_keys = keys;
		{
			LoadSortData(temp_keys, m_sortinfos, recordSize, reader);
		}

		{
			m_comp_count = 0;
			std::sort(m_indexes.begin(), m_indexes.end(), Comparator(*this));
		}

		char* record = m_buffer;
		{
			Q_ASSERT(m_indexes.size() == temp_keys.size());
			for (int i = 0; i < (int)temp_keys.size(); i++)
			{
				KeyType* pkey= *(reinterpret_cast<KeyType**>(record + m_indexes[i].offset));
				//KeyType& bki = *((KeyType*)(record + m_indexes[i].offset));
				keys[i] = *pkey;
			}
		}
	}


}